tags:
- Notes
ISA, Instructions and CPU
我们都明白,计算机系统可以分成两类功能上的实体——计算机硬件、计算机软件。但是软件和硬件是两个很宽泛的概念,继续划分,我们可以将整个计算机系统划分成 7 层结构:
在我们学习操作系统的时候,可能会听老师说:“操作系统是介于软件和硬件之间最接近硬件的软件,为软件间接提供操作硬件的接口“。通过上面对ISA极其模糊的介绍之后,你会不会有很多关于ISA和操作系统的疑惑?我们下面来看看ISA究竟是什么东西。
ISA是指令集体系结构,它对于硬件而言是一种设计上的规约,而对于操作系统而言ISA提供API的接口。我们常听说ARM、MIPS、x86等这些就对应着不同的ISA。既然叫指令集体系结构,那它肯定和指令有着密不可分的关系,对于硬件来说,ISA是一种规约,它规定了CPU需要为哪些指令提供接口(例如:加减乘除与或非),而至于具体的实现?那完全是微体系结构的事情。(ISA关心的是有没有乘法器、乘法指令的事情,微体系结构关心的是乘法器如何实现的事情。)
我们举例子直观来感受一下ISA对上层操作系统提供的指令集接口,我们用ARM和x86举例子:
加载寄存器
LDR R0, [R1]
1110 0101 1000 0000 0000 0000 0000 0000
MOV EAX, [EBX]
1000 1011 0000 0000
加法操作
ADD R0, R1, R2
1110 0000 1000 0001 0000 0000 0000 0010
ADD EAX, EBX
0000 0001 1100 0011
存储寄存器
- **ARM**: `STR R0, [R1]`
- 二进制表示: `1110 0101 0000 0000 0000 0000 0000 0000`
- **x86**: `MOV [EBX], EAX`
- 二进制表示: `1000 1001 0000 0000`
发现了么?ISA不同,实现相同功能的指令就是不一样的。这也就是为什么你写的程序不能在其他平台上运行,这里的平台指的就是ISA。
如果我们的只有定长的8位指令,我们如何设计自己的ISA?我们下面给出规约:
系统应当有6个寄存器(REG0-REG5),一个输入端,一个输出端。
用高两位用来表示指令的类型:
00
表示立即数指令,我们规定立即数指令总是将立即数送给REG0;
01
表示计算指令,这部分指令由ALU实现,我们进行如下规定:
01 000 000
表示OR
指令01 000 001
表示NAND
指令01 000 010
表示NOR
指令01 000 011
表示AND
指令01 000 100
表示ADD
指令01 000 101
表示SUB
指令我们可以向立即数指令一样,设置某个特定的寄存器用于特定的作用,如:算数操作永远是将REG1和REG2中读取数值作为输入的操作数,并将结果写入REG3中。
10
表示复制指令,将源的数据送到目的,我们进行如下规定:
10 000(SRC) 000(DEST)
高两位表示类型,中间三位表示源,后三位表示目的。000
-101
表示从REG0-REG5的寄存器,中间三位为110
时表示从输入端读数据,后三位为110
时表示将源数据送到输出端。11
表示条件判断指令,只有满足条件才会将数据输出,我们给出如下规定:
11 000 000
表示永不输出11 000 001
表示输入=0
时输出11 000 010
表示输入<0
时输出11 000 011
表示输入≤0
时输出11 000 100
表示永远输出11 000 101
表示输入≠0
时输出11 000 111
表示输入>0
时输出汇编,我们可以理解为机器码的别名,每一条汇编指令都可以对于某一个特定的指令。依此,我们可以将机器码通过添加汇编别名方便地为人类理解,如:
add ;01 000 100
sub ;01 000 101
mov_reg0_reg5 ;10 000 101
mov_in_out ;10 110 110
等等。看到了么?在我们的指令系统中,操作系统可以用add
指令来与底层的裸机进行交互,告诉机器我现在要让你把REG1和REG2的数据相加放到REG3中。
根据上面我们的指令集体系结构的规约,我们就可以设计自己的CPU了。
首先,我们需要译码器帮助我们用高两位将不同功能的指令给筛选出来,这里,我们简单用分线器将 8 位指令分成 8 个输入端,取高两位用2-4译码器来完成译码的工作。当高两位为00
就使能立即数操作的工作逻辑,为01
就使能ALU,以此类推。